package com.thiswhyme.demo.msgpush.core.impl.websocket;

import cn.hutool.json.JSONUtil;
import com.thiswhyme.common.utils.UrlParamUtils;
import com.thiswhyme.demo.msgpush.core.WsConstant;
import com.thiswhyme.demo.msgpush.core.event.bean.EventType;
import com.thiswhyme.demo.msgpush.core.event.bean.WebSocketEvent;
import com.thiswhyme.redis.subscribe.RedisPublisher;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.net.URI;
import java.util.Collections;
import java.util.Map;

/**
 * @description: WebSocket请求处理器
 * @author: thiswhyme
 * @date: 2021/9/27
 */
@Slf4j
@AllArgsConstructor
public class DefaultWebSocketHandler extends AbstractWebSocketHandler {

    private final RedisPublisher redisPublisher;

    /**
     * socket连接成功处理
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        URI uri = session.getUri();
        if (null == uri) {
            throw new RuntimeException("无法识别登录用户");
        }

        Map<String, Object> params = UrlParamUtils.queryToMap(uri.getQuery());
        Object tokenObj = params.get(WsConstant.WS_TOKEN);
        String token = null == tokenObj ? "" : tokenObj.toString();

        if (!StringUtils.isEmpty(token)) {
            session.getAttributes().put(WsConstant.WS_SESSION_IDENTIFIER, token);
            SessionManager.add(token, session);

            WebSocketEvent event = new WebSocketEvent()
                    .setIdentifiers(Collections.singletonList(token))
                    .setEventType(EventType.CONNETCT)
                    .setMsgContent(session.getId());
            redisPublisher.publish(WsConstant.WS_MSG_PUSH_CHANNEL, JSONUtil.toJsonStr(event));
        } else {
            throw new RuntimeException("无法识别登录用户");
        }
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 心跳消息处理
        if (WsConstant.HEARTBEAT_PING.equals(message.getPayload())) {
            String token = session.getAttributes().get(WsConstant.WS_SESSION_IDENTIFIER).toString();
            log.debug("收到【{}】的心跳消息", token);
            WebSocketEvent event = new WebSocketEvent()
                    .setIdentifiers(Collections.singletonList(token))
                    .setEventType(EventType.PUSH).setMsgContent(WsConstant.HEARTBEAT_PONG);;
            redisPublisher.publish(WsConstant.WS_MSG_PUSH_CHANNEL, JSONUtil.toJsonStr(event));
        }
    }

    /**
     * socket断开连接处理
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        Object token = session.getAttributes().get(WsConstant.WS_SESSION_IDENTIFIER);
        if (token != null) {
            WebSocketEvent event = new WebSocketEvent()
                    .setIdentifiers(Collections.singletonList(token.toString()))
                    .setEventType(EventType.COLSE)
                    .setMsgContent(session.getId());
            redisPublisher.publish(WsConstant.WS_MSG_PUSH_CHANNEL, JSONUtil.toJsonStr(event));
        }
    }
}
